package cn.aiweiyi.qingjing.coupon.settlement.executor;

import cn.aiweiyi.qingjing.coupon.comm.vo.GoodsInfo;
import cn.aiweiyi.qingjing.coupon.comm.vo.SettlementInfo;
import cn.aiweiyi.qingjing.coupon.settlement.util.BigDecimalUtils;
import com.alibaba.fastjson.JSON;
import org.apache.commons.collections4.CollectionUtils;
import org.aspectj.lang.annotation.SuppressAjWarnings;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <h1>规则执行器抽象类，定义通用方法</h1>
 * 抽象执行器
 */
public abstract class AbstractExecutor {
    /**
     * 效验商品类型与优惠券是否匹配
     * 这里实现的是单品类优惠券的效验，如果需要效验多种，请重写此方法
     *
     * @param settlementInfo
     * @return
     */
    @SuppressAjWarnings("all")
    protected boolean isGoodsTypeSatisfy(SettlementInfo settlementInfo) {
        // 把结算信息中的商品类型集合id取出，作为集合
        List<Integer> goodsType = settlementInfo.getGoodsInfos().stream()
                .map(GoodsInfo::getType).collect(Collectors.toList());
        // 把所有模板中的规则中使用范围中的商品类型取出
        List<Integer> templateGoodsType = JSON.parseObject(
                settlementInfo.getCouponAndTemplateInfos().get(0).getTemplate()
                        .getRule().getUsage().getGoodsType(), List.class
        );
        // 返回两个集合的交集，先判断
        return CollectionUtils.isNotEmpty(
                CollectionUtils.intersection(goodsType, templateGoodsType));
    }

    /**
     * 处理商品类型与优惠券限制不匹配的情况
     *
     * @param settlementInfo 用户传递的结算信息
     * @param goodsSum       商品总价
     * @return 已修改过的结算信息
     */
    protected SettlementInfo processGoodsTypeNotSatisfy(SettlementInfo settlementInfo, double goodsSum) {
        boolean isGoodsTypeSatisfy = isGoodsTypeSatisfy(settlementInfo);
        // 当商品类型不满足时，直接返回商品总价，并清空优惠券
        if (!isGoodsTypeSatisfy) {
            settlementInfo.setCost(goodsSum);
            settlementInfo.setCouponAndTemplateInfos(Collections.emptyList());
            return settlementInfo;
        }
        return null;
    }

    /**
     * 循环累加，计算商品总价，使用BigDecimal来计算金额（浮点型）比较准确
     *
     * @param goodsInfos 商品集合
     * @return
     */
    protected double goodsCostSum(List<GoodsInfo> goodsInfos) {
        //return goodsInfos.stream().mapToDouble(g -> g.getPrice() * g.getCount()).sum();
        // 使用BigDecimal精确的浮点型运算
        double sum = 0;
        for (GoodsInfo g : goodsInfos) {
            // 使用BigDecimalUtil工具类来计算，小计
            double money = BigDecimalUtils.multiply(g.getPrice(), g.getCount());
            // 累加
            sum = BigDecimalUtils.add(money, sum);
        }
        return sum;
    }

    /**
     * 四舍五入，保留两位小数
     *
     * @param value
     * @return
     */
    protected double retain2Decimals(double value) {
        return new BigDecimal(value).setScale(2, BigDecimal.ROUND_HALF_UP)
                .doubleValue();
    }

    /**
     * 最小支付费用
     *
     * @return
     */
    protected double minCost() {
        return 0.1;
    }

}
